package logic;


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.xml.sax.SAXException;

public class ItemFactory {

	protected Property m_Property;
	
	protected SAXParser m_SaxParser;
	protected Schema m_Schema;
	
	protected ItemHandler m_ItemHandler;
	
	protected HashMap<String, Object> m_Objects;
	
	public ItemFactory(Property property) {
		m_Property = property;
		m_Objects = new HashMap<String, Object>();
	}
	
	/**
	 * Validates given file name based on the meta data
	 * defined in the property instance variable.
	 * @param fileName
	 * @return
	 */
	public boolean validate(String fileName) {
		
		Validator validator;
		
		// Init the sax-parser and the schema for validation purposes.
		initXmlParser();
		validator = m_Schema.newValidator();
		
		try {
			validator.validate(new StreamSource(new FileInputStream(fileName)));
			
		} catch (SAXException e) {
			System.out.println(fileName + " is not valid.");
			return false;
			
		} catch (IOException e) {
			System.out.println("IOException occured. Try the validation again.");
			return false;
		}
		return true;
	}
	
	/**
	 * Parses the given fileName based on the meta data
	 * defined in the property instance variable.
	 * @param fileName
	 * @throws Exception
	 */
	public int parse(String fileName) throws Exception {
		
		// Init the sax-parser and the schema for validation purposes.
		initXmlParser();
		
		/*
		 * Parse the content of the file. In case of any 
		 * exception the exception is thrown to the upper
		 * layer.
		 */
		m_SaxParser.parse(fileName, m_ItemHandler);
		
		return m_Objects.size();
	}
	
	/**
	 * Initialises the XML-parser based on the meta
	 * data in the property instance variable.
	 * 
	 * The meta data key 'xmlSchemaUri' in the property 
	 * instance variable specifies in this regards the
	 * XML-Schema of the coming file to parse.
	 *
	 */
	protected void initXmlParser() {
		
		String language, xmlSchemaUri;
		SchemaFactory factory;
		StreamSource streamSource;
		SAXParserFactory saxParserFactory;
		
		// Get the xml-schema-uri in order to make a validation later on.
		xmlSchemaUri = m_Property.getProperty("xmlSchemaUri") + "";
		
		try {
			
			if (m_SaxParser == null &&
					m_Schema == null) {
				
				// Initialize the sax parser.
				saxParserFactory = SAXParserFactory.newInstance();
				saxParserFactory.setValidating(true);
				m_SaxParser = saxParserFactory.newSAXParser();
				
				// Initialize schema for validation purposes.
				language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
				factory = SchemaFactory.newInstance(language);
				factory.setErrorHandler(m_ItemHandler);
				streamSource = new StreamSource(new File(xmlSchemaUri));
				m_Schema = factory.newSchema(streamSource);
			}
			
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}
	
	public HashMap<String, Object> getObjects() {
		return m_Objects;
	}

}
